Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Web
Imports System.Xml
Imports System.Xml.XPath

Public MustInherit Class Request

#Region "shared"

    Public Const DEFAULT_TIMEOUT As Integer = 100000
    Public Const INFINITE_TIMEOUT As Integer = Threading.Timeout.Infinite

    Public Enum RequestType
        Information
        File
        Session
    End Enum

    Private Shared ReadOnly REQUEST_DOC_TYPE As New Dtd("request.dtd", "request")
    Private Shared ReadOnly XPATH_REQUEST_TYPE As XPathExpression = XPathExpression.Compile("/request/@type")
    Private Shared ReadOnly XPATH_MODALITY As XPathExpression = XPathExpression.Compile("/request/item[@name = 'modality']")
    Private Shared ReadOnly XPATH_MODEL As XPathExpression = XPathExpression.Compile("/request/item[@name = 'model']")
    Private Shared ReadOnly XPATH_TOOL As XPathExpression = XPathExpression.Compile("/request/item[@name = 'tool']")
    'Private Const FILENAME_PATTERN As String = "attachment(?:;.*?)*?(?:;\s*filename\s*=\s*(?:""(?<filename>[^""]*)""|(?<filename>[^"";]*)\s*))"
    'Private Shared ReadOnly FILENAME_REGEX As New Regex(FILENAME_PATTERN)

    Public Shared Function Parse(ByVal xml As String) As Request

        Dim r As Request

        If xml Is Nothing OrElse xml.Length = 0 Then
            Return Nothing
        End If

        'Dim xmlWithoutDtd As String = XmlString.RemoveDocType(xml)
        'REQUEST_DOC_TYPE.Validate(xmlWithoutDtd)

        'Dim xr As XmlReader = XmlString.GetXmlReader(xmlWithoutDtd)
        Dim xr As XmlReader = REQUEST_DOC_TYPE.GetValidatingReader(xml)

        Dim xd As New XPathDocument(xr)
        Dim xn As XPathNavigator = xd.CreateNavigator()
        Dim type As String = xn.SelectSingleNode(XPATH_REQUEST_TYPE).Value
        Select Case type
            Case "information"
                r = New InformationRequest(xn, xml)
            Case "file"
                r = New FileRequest(xn, xml)
            Case "session"
                r = New SessionRequest(xn, xml)
            Case Else
                r = Nothing
        End Select

        Return r

    End Function

    Private Shared Function GetModality(ByVal xn) As String

        Dim xnX As XPathNavigator = xn.SelectSingleNode(XPATH_MODALITY)
        If xnX Is Nothing Then
            Throw New ApplicationException("modality code expected")
        End If

        Return xnX.Value

    End Function

    Private Shared Function GetModel(ByVal xn) As String

        Dim xnX As XPathNavigator = xn.SelectSingleNode(XPATH_MODEL)
        If xnX Is Nothing Then
            Throw New ApplicationException("model id expected")
        End If

        Return xnX.Value

    End Function

    Private Shared Function GetTool(ByVal xn) As String

        Dim xnX As XPathNavigator = xn.SelectSingleNode(XPATH_TOOL)
        If xnX Is Nothing Then
            Throw New ApplicationException("service tool type expected")
        End If

        Return xnX.Value

    End Function
#End Region

#Region "instance"

    Private _Type As RequestType
    Private _XmlStr As String

    Private _Modality As String
    Private _Model As String
    Private _Tool As String

    Private _Timeout As Integer

    Protected Sub New(ByVal xn As XPathNavigator, ByVal type As RequestType, ByVal xmlStr As String)

        _Type = type
        _XmlStr = xmlStr

        _Modality = GetModality(xn)
        _Model = GetModel(xn)
        _Tool = GetTool(xn)

        _Timeout = INFINITE_TIMEOUT

    End Sub

    Public Property Timeout() As Integer
        Get
            Return _Timeout
        End Get
        Set(ByVal value As Integer)
            _Timeout = value
        End Set
    End Property

    Public ReadOnly Property Type() As RequestType
        Get
            Return _Type
        End Get
    End Property

    Public ReadOnly Property XmlStr() As String
        Get
            Return _XmlStr
        End Get
    End Property

    Public ReadOnly Property Modality() As String
        Get
            Return _Modality
        End Get
    End Property

    Public ReadOnly Property Model() As String
        Get
            Return _Model
        End Get
    End Property

    Public ReadOnly Property Tool() As String
        Get
            Return _Tool
        End Get
    End Property

    Public Function Send(ByVal address As String) As Response

        Dim resp As Response

        Dim requestString As String = "request=" & HttpUtility.UrlEncode(_XmlStr)
        Dim requestData() As Byte = Encoding.ASCII.GetBytes(requestString)
        'Dim requestData() As Byte = HttpUtility.UrlEncodeToBytes(requestString)
        'Dim s As String = Encoding.ASCII.GetString(requestData)
        'Dim t As String = HttpUtility.UrlDecode(requestData, Encoding.ASCII)

        Dim uri As New Uri(address)
        Dim request As HttpWebRequest = HttpWebRequest.Create(uri)
        request.Timeout = _Timeout
        request.Method = WebRequestMethods.Http.Post
        request.ContentType = "application/x-www-form-urlencoded"
        request.ContentLength = requestData.Length
        With request.GetRequestStream
            .Write(requestData, 0, requestData.Length)
            '.Close()
        End With

        Try
            Dim r As HttpWebResponse = request.GetResponse()
            resp = DoResponse(r)
        Catch ex As WebException
            If ex.Response Is Nothing Then
                Throw ex
            End If

            Dim statusCode As HttpStatusCode = CType(ex.Response, HttpWebResponse).StatusCode
            resp = New Response(statusCode)
        End Try

        Return resp

    End Function

    Protected MustOverride Function DoResponse(ByVal r As HttpWebResponse) As Response
#End Region
End Class
